﻿// Stickers
// An example app demonstrating cloud native .NET apps
// Written by daxnet (Sunny Chen)
// MIT License
// 2024

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Stickers.Common.Authorization;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ProtectedResourceAttribute(string resourceName, params string[] allowedScopes)
: Attribute, IAsyncAuthorizationFilter
{
    public string ResourceName { get; } = resourceName;
 
    public string[] AllowedScopes { get; } = allowedScopes;
    
    public Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        var user = context.HttpContext.User;
        if (user is { Identity.IsAuthenticated: false })
        {
            // 若未认证，返回403
            context.Result = new ForbidResult();
        }
        else
        {
            // 从user claims中获得与当前资源名称相同的permission claim
            var permissionClaim = user.Claims.FirstOrDefault(c => c.Type == $"res:{ResourceName}");
            if (permissionClaim is not null)
            {
                // 若存在permission claim
                if (AllowedScopes.Length == 0)
                {
                    // 并且在当前资源上并未定义所支持的scope，则说明任何scope都可以接受，直接返回
                    return Task.CompletedTask;
                }
 
                // 否则，检查permission claim中是否有包含当前资源所支持的scope
                var permittedScopes = permissionClaim.Value.Split(',');
 
                // 如果不存在，则返回403
                if (permittedScopes.Length == 0 || !AllowedScopes.Intersect(permittedScopes).Any())
                {
                    context.Result = new ForbidResult();
                }
            }
            else
            {
                // 如果user claims中不存在与当前资源对应的permission claim，则返回403
                context.Result = new ForbidResult();
            }
        }
 
        return Task.CompletedTask;
    }
}